#include<iostream>
#include <unordered_map>
#include <map>
#include "rocksdb/slice.h"
/*
// global: 
inline bool operator==(const Slice& x, const Slice& y) ;
inline bool operator!=(const Slice& x, const Slice& y) ;
class Slice {
public:
// member:
  Slice();
  Slice(const char* s);
  Slice(const char* d, size_t n);
  Slice(const std::string& s);
  Slice(std::string_view sv);
  Slice(const struct SliceParts& parts, std::string* buf);

//readonly data property:
  const char* data() const; 
  size_t size() const;
  bool empty() const;
  char operator[](size_t n) const;

  void clear();
  void remove_prefix(size_t n);
  void remove_suffix(size_t n);

  int compare(const Slice& b) const;
  size_t difference_offset(const Slice& b) const;
  bool starts_with(const Slice& x) const;
  bool ends_with(const Slice& x) const;

  std::string ToString(bool hex = false) const;
  std::string_view ToStringView() const;

private:
//data field:
  const char* data_; //const for readonly
  size_t size_;

  bool DecodeHex(std::string* result) const; //helper function
}; //Slice end
*/


using rocksdb::Slice;
namespace std {
    template<> struct hash<Slice> {
        std::size_t operator()(const Slice & sc) const {
            unsigned long hash = 0U;
            for(size_t i = 0; i < sc.size(); ++i) {
                hash = ((hash << 5) + hash) + (unsigned long)sc.data()[i]; 
            }
            return static_cast<std::size_t>(hash);
        }
    };
}


void testSlice(){
    //1.  constructor
    Slice empty;
    assert(empty.empty());
    Slice s("slice-test-hello");
    assert(s.size() > 0);

    std::cout << s.ToString() << " data:" << s.data() << std::endl;
    std::cout << s.ToString(true) << std::endl;
    
    //2. copy constructor default
    empty = s;
    assert(empty == s);

    Slice n(s);
    assert(n == s);
    std::cout << n.ToString() << std::endl;
    std::cout << n.ToString(true) << std::endl;

    //3. use slice as function parameter
    {
        auto f = [](const Slice & s){
            std::cout << s.ToString() << std::endl;
        };
        f(s);
        f("hello-from-cstring to const String &");
    }
    //4. use rvalue slice as function parameter
    {
        auto fref = [](Slice && s){
            std::cout << s.ToString() << std::endl;
        };
        fref(Slice("hello-world-from")); //rvalue -> rvalue
        fref("hello-from-cstring"); // rvalue -> rvalue
        fref(std::move(s));  // cast lvalue -> rvalue
    }
    //5. use Slice with STL unordered_map
    {
        std::cout << std::hash<Slice>{}("Hello") << std::endl;
        std::unordered_map<const Slice, std::string, std::hash<Slice>> map  = {
            {"Hello", "worldHash"},
            {"Hello1", "world1Hash"},
            {"Hello2", "world2Hash"},
        };

        auto read = [map](const Slice & key) -> Slice {
            return Slice(map.at(key));
        };
        std::cout << read("Hello").ToString() << std::endl;
    }

    //6. use Slice with STL ordered_map
    {
        struct SliceCompare{
            bool operator()(const Slice & left, const Slice & right) const{
                return left.compare(right) < 0;
            }
        };
        std::map<const Slice, std::string, SliceCompare> map = {
            {"Hello", "worldMap"},
            {"Hello1", "world1Map"},
            {"Hello2", "world2Map"},
        };
        auto read = [map](const Slice & key) -> Slice {
            return Slice(map.at(key));
        };
        std::cout << read("Hello").ToString() << std::endl;
    }

    {
        //Function ( slice)
        //Func() -> slice
        //slice = slice
        //slice == slice
        //std::map<slice>
        //std::unordered_map<slice>
    }

}

int main(){
    testMyString();
    testSlice();
    return 0;
}




